package com.smedi.ismedi.personnel.core.application.service.impl;

import cn.hutool.core.util.IdUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.smedi.ismedi.cache.starter.util.RedisUtil;
import com.smedi.ismedi.organization.api.dto.response.ProjectOrganizationResponse;
import com.smedi.ismedi.personnel.core.application.command.PersonAssigmentCommand;
import com.smedi.ismedi.personnel.core.application.command.PersonBasicCommand;
import com.smedi.ismedi.personnel.core.application.command.ProjectAssigmentCommand;
import com.smedi.ismedi.personnel.core.application.service.PersonApplicationService;
import com.smedi.ismedi.personnel.core.application.service.UploadDataApplicationService;
import com.smedi.ismedi.personnel.core.domain.aggregatemodel.Person;
import com.smedi.ismedi.personnel.core.domain.aggregatemodel.UploadPersonTemplateRow;
import com.smedi.ismedi.personnel.core.domain.aggregatemodel.UploadPersonTemplateValidate;
import com.smedi.ismedi.personnel.core.domain.service.PersonDomainService;
import com.smedi.ismedi.personnel.core.infrastructure.constant.ConstantField;
import com.smedi.ismedi.personnel.core.infrastructure.constant.CustomError;
import com.smedi.ismedi.personnel.core.infrastructure.enumerate.GenderEnum;
import com.smedi.ismedi.personnel.core.infrastructure.enumerate.PersonStatusEnum;
import com.smedi.ismedi.personnel.core.infrastructure.enumerate.PersonTypeEnum;
import com.smedi.ismedi.personnel.core.port.adapter.service.ConstructionProjectRemoteApiService;
import com.smedi.ismedi.personnel.core.port.adapter.service.OrganizationRemoteApiService;
import com.smedi.ismedi.web.starter.exception.LogicException;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.poi.xssf.usermodel.XSSFCell;
import org.apache.poi.xssf.usermodel.XSSFSheet;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
import org.springframework.web.multipart.MultipartFile;

import java.io.IOException;
import java.io.InputStream;
import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Optional;

/**
 * @Author: xulinjun
 * @Date: 2021-6-12 14:54
 */
@Slf4j
@Service
@AllArgsConstructor
public class UploadDataApplicationServiceImpl implements UploadDataApplicationService {
    private final OrganizationRemoteApiService organizationRemoteApiService;

    private final PersonDomainService personDomainService;

    private final RedisUtil redisUtil;

    private final PersonApplicationService personApplicationService;

    private final ConstructionProjectRemoteApiService constructionProjectRemoteApiService;

    private String[] templateColumns = {"所属组织", "姓名", "手机号", "性别", "工号/编号", "职务", "邮箱", "办公电话", "身份证号"};

    /**
     * 获取单元格数据
     *
     * @param cell
     * @return
     */
    private String getCellValue(XSSFCell cell) {
        try {
            return cell.getStringCellValue();
        } catch (Exception e) {
            return null;
        }
    }

    /**
     * 读取模板数据
     *
     * @param file
     * @param projectId
     * @param internal
     * @return
     * @throws IOException
     */
    private List<UploadPersonTemplateRow> readTemplate(MultipartFile file, Long projectId, boolean internal) throws IOException {
        List<UploadPersonTemplateRow> list = new ArrayList<>();
        InputStream is = file.getInputStream();
        XSSFWorkbook wb = new XSSFWorkbook(is);
        XSSFSheet sheet = wb.getSheetAt(0); // 只获取第一个页签
        if (sheet != null) {
            // 最大导入行数限制
            if (sheet.getLastRowNum() <= ConstantField.maxTemplateRow) {
                if (sheet.getLastRowNum() >= 0 && sheet.getRow(0).getPhysicalNumberOfCells() >= 1) {
                    // 不填写数据则报错
                    if (sheet.getLastRowNum() == 0) {
                        throw LogicException.raise(CustomError.EXCEL_EMPTY_ERROR);
                    }

                    // 循环获取模板数据
                    for (int i = 0; i <= sheet.getLastRowNum(); i++) {
                        if (i == 0) {
                            // 校验导入标题字段是否与定义的字段一致
                            for (int j = 0; j < templateColumns.length; j++) {
                                String column = getCellValue(sheet.getRow(i).getCell(j));
                                if (!templateColumns[j].equals(column)) {
                                    throw LogicException.raise(CustomError.EXCEL_TEMPLATE_ERROR);
                                }
                            }
                        } else {
                            List<String> datas = new ArrayList();
                            boolean allNull = true;
                            for (int z = 0; z <= 8; z++) {
                                String value = getCellValue(sheet.getRow(i).getCell(z));
                                datas.add(value);

                                allNull = StringUtils.isEmpty(value);
                            }

                            // 避免全空的情况
                            if (!allNull) {
                                String organizationName = datas.get(0); // 组织名称
                                String jobName = datas.get(5); // 职务名称
                                UploadPersonTemplateRow row = new UploadPersonTemplateRow()
                                        .setLastName(datas.get(1))
                                        .setMobile(datas.get(2))
                                        .setGenderName(datas.get(3))
                                        .setEmployeeNum(datas.get(4))
                                        .setEmail(datas.get(6))
                                        .setOfficeTelephone(datas.get(7))
                                        .setIdCard(datas.get(8));

                                // 根据是否企业人员对于部分字段特殊处理
                                if (internal) {
                                    row.setHrOrganizationName(organizationName)
                                            .setHrJob(jobName);
                                } else {
                                    row.setProjectOrganizationName(organizationName)
                                            .setProjectJob(jobName)
                                            .setProjectId(projectId);
                                }
                                list.add(row);
                            }
                        }
                    }
                } else {
                    throw LogicException.raise(CustomError.EXCEL_EMPTY_ERROR);
                }
            } else {
                throw LogicException.raise(CustomError.EXCEL_MAX_ROW_ERROR);
            }
        } else {
            throw LogicException.raise(CustomError.EXCEL_SHEET_MISS);
        }
        return list;
    }

    /**
     * 导入接口只考虑新建人员，已存在的人员则通过前台页面进行操作
     *
     * @param list
     * @param orgMaps
     * @param internal
     */
    private void doPersonValidate(List<UploadPersonTemplateRow> list, Map<Long, String> orgMaps, boolean internal) {
        for (UploadPersonTemplateRow i : list) {
            log.info("i: {}", JSONObject.toJSONString(i));

            String error = "";
            boolean validated = false;

            // 字段必填以及格式校验
            if (StringUtils.isEmpty(i.getLastName())) {
                error += "姓名为空；";
            }
            if (StringUtils.isEmpty(i.getMobile())) {
                error += "手机号为空；";
            } else {
                if (!personDomainService.validateMobileFormat(i.getMobile())) {
                    error += "手机号格式错误；";
                }
            }
            if (StringUtils.isEmpty(i.getGenderName())) {
                error += "性别为空；";
            } else {
                String gender = GenderEnum.getValue(i.getGenderName());
                if (StringUtils.isEmpty(gender)) {
                    error += "性别值列表不匹配！";
                } else i.setGender(gender);
            }
            if (StringUtils.isEmpty(i.getIdCard())) {
                error += "身份证号为空；";
            } else {
                if (!personDomainService.validateIdCardFormat(i.getIdCard())) {
                    error += "身份证格式错误；";
                }
            }
            if (!StringUtils.isEmpty(i.getEmail())) {
                if (!personDomainService.validateEmailFormat(i.getEmail())) {
                    error += "邮箱格式错误；";
                }
            }

            // 判断企业组织与项目组织的信息
            if (internal) {
                if (StringUtils.isEmpty(i.getHrOrganizationName())) {
                    error += "所属企业组织为空；";
                } else {
                    // 判断所属组织是否在当前所选组织的节点树中
                    if (!orgMaps.containsValue(i.getHrOrganizationName())) {
                        error += "所属企业组织不属于当前节点的企业组织树下；";
                    } else {
                        // 根据组织名称获取到组织id
                        Optional<Map.Entry<Long, String>> org = orgMaps.entrySet().stream().filter(a -> a.getValue().equals(i.getHrOrganizationName())).findFirst();
                        i.setHrOrganizationId(org.get().getKey()); // 企业组织id
                    }
                }
            } else {
                if (StringUtils.isEmpty(i.getProjectOrganizationName())) {
                    error += "所属项目组织为空；";
                } else {
                    // 判断所属组织是否在当前所选组织的节点树中
                    if (!orgMaps.containsValue(i.getProjectOrganizationName())) {
                        error += "所属项目组织不属于当前节点的项目组织树下；";
                    } else {
                        // 根据组织名称获取到组织id
                        Optional<Map.Entry<Long, String>> org = orgMaps.entrySet().stream().filter(a -> a.getValue().equals(i.getProjectOrganizationName())).findFirst();
                        i.setProjectOrganizationId(org.get().getKey()); // 项目组织id
                    }
                }
            }

            // 校验人员信息
            if (StringUtils.isEmpty(error)) {
                // 根据身份证号判断该人员是否存在
                Person person = personDomainService.queryByIdCard(i.getIdCard());
                if (person != null) {
                    error += "身份证已存在；";
                }
                // 导入企业人员需要判断员工号是否重复
                if (internal) {
                    if (!StringUtils.isEmpty(i.getEmployeeNum())) {
                        if (personDomainService.duplicateEmployeeNum(i.getEmployeeNum(), null)) {
                            error += "员工号重复；";
                        }
                    }
                }
                // 手机号是否重复
                if (personDomainService.duplicateMobile(i.getMobile(), null)) {
                    error += "手机号重复；";
                }
            }
            // 判断校验结果
            if (StringUtils.isEmpty(error)) {
                validated = true;
            }
            i.setValidated(validated).setErrorMessage(error);
        }
    }

    @Override
    public UploadPersonTemplateValidate doUpload(MultipartFile file, Long organizationId, Long projectId, Boolean internal) throws IOException {
        if (organizationId == null) {
            throw LogicException.raise(CustomError.ORG_ID_MISS);
        }
        if (!internal) {
            if (projectId == null) {
                throw LogicException.raise(CustomError.PROJECT_ID_MISS);
            }
        }

        // 判断传入的组织id是否存在
        if (internal ? !(organizationRemoteApiService.checkHrOrganizationAvailable(organizationId)) : !(organizationRemoteApiService.checkProjectOrganizationAvailable(organizationId))) {
            throw LogicException.raise(CustomError.ORG_NOT_AVAILABLE);
        }

        // 导入项目人员时校验项目id是否有效
        if (!internal) {
            if (!constructionProjectRemoteApiService.checkProjectAvailable(projectId)) {
                throw LogicException.raise(CustomError.PROJECT_NOT_AVAILABLE);
            } else {
                // 判断项目组织的项目id是否与传入的项目id一致
                ProjectOrganizationResponse projectOrganizationResponse = organizationRemoteApiService.getProjectOrganizationView(organizationId);
                if (!projectOrganizationResponse.getProjectId().equals(projectId)) {
                    throw LogicException.raise(CustomError.PROJECT_ORGANIZATION_NOT_BELONG_PROJECT);
                }
            }
        }

        // 获取该组织节点下的所有子组织
        Map<Long, String> maps = internal ? organizationRemoteApiService.getHrOrganizationChildrenOrgMap(organizationId) : organizationRemoteApiService.getProjectOrganizationChildrenMap(organizationId);

        // 读取数据
        List<UploadPersonTemplateRow> list = readTemplate(file, projectId, internal);

        // 校验数据
        doPersonValidate(list, maps, internal);

        // 生成唯一的uuid
        String uuid = IdUtil.simpleUUID();
        // 判断是否有复核的记录
        Optional<UploadPersonTemplateRow> optional = list.stream().filter(i -> !i.isValidated()).findFirst();
        boolean allValidate = !optional.isPresent();

        UploadPersonTemplateValidate uploadPersonTemplateValidate = new UploadPersonTemplateValidate().setAllValidated(allValidate)
                .setUploadPersonTemplateRows(list)
                .setInternal(internal)
                .setValidateId(uuid);

        // 拥有一定有效期，过期了则自动删除
        redisUtil.set(ConstantField.uploadDataValidateTempPath + uuid, JSONObject.toJSONString(uploadPersonTemplateValidate), ConstantField.uploadDataValidateTempLive);

        return uploadPersonTemplateValidate;
    }

    @Override
    public UploadPersonTemplateValidate doConfirmValidateAndSubmit(String validateId) {
        boolean allSaved = true;
        // 获取数据
        String jsonStr = (String) redisUtil.get(ConstantField.uploadDataValidateTempPath + validateId);
        if (StringUtils.isEmpty(jsonStr)) {
            throw LogicException.raise(CustomError.VALIDATE_DATA_MISS);
        } else {
            UploadPersonTemplateValidate uploadPersonTemplateValidate = JSON.parseObject(jsonStr, UploadPersonTemplateValidate.class);
            // 判断是否全部校验通过
            if (!uploadPersonTemplateValidate.isAllValidated()) {
                throw LogicException.raise(CustomError.NOT_ALL_VALIDATE);
            }

            if (!uploadPersonTemplateValidate.getValidateId().equals(validateId)) {
                throw LogicException.raise(CustomError.VALIDATE_ID_NOT_THE_SAME);
            } else {
                // 导入数据
                for (UploadPersonTemplateRow row : uploadPersonTemplateValidate.getUploadPersonTemplateRows()) {
                    PersonBasicCommand personBasicCommand = new PersonBasicCommand().setPersonType(uploadPersonTemplateValidate.isInternal() ? PersonTypeEnum.COMPANY_MEMBER.getValue() : PersonTypeEnum.PROJECT_MEMBER.getValue())
                            .setEmail(row.getEmail())
                            .setGender(row.getGender())
                            .setIdCard(row.getIdCard())
                            .setOfficeTelephone(row.getOfficeTelephone())
                            .setEmployeeNum(row.getEmployeeNum())
                            .setLastName(row.getLastName())
                            .setMobile(row.getMobile())
                            .setStatus(PersonStatusEnum.ENABLE.getValue()); // 默认启用

                    if (uploadPersonTemplateValidate.isInternal()) {
                        // 企业人员数据保存
                        personBasicCommand.setPersonAssigmentCommand(new PersonAssigmentCommand()
                                .setHrJob(row.getHrJob())
                                .setHrOrganizationId(row.getHrOrganizationId()));
                        try {
                            personApplicationService.saveInternalPerson(personBasicCommand); // 企业人员
                            row.setSaved(true);
                        } catch (Exception e) {
                            allSaved = false;
                            row.setSaved(false);
                            row.setErrorMessage(e.getMessage());
                        }
                    } else {
                        // 项目人员数据保存
                        personBasicCommand.setProjectAssigmentCommand(new ProjectAssigmentCommand()
                                .setProjectId(row.getProjectId())
                                .setProjectJob(row.getProjectJob())
                                .setProjectOrganizationId(row.getProjectOrganizationId()));
                        try {
                            personApplicationService.saveExternalPerson(personBasicCommand);
                            row.setSaved(true);
                        } catch (Exception e) {
                            allSaved = false;
                            row.setSaved(false);
                            row.setErrorMessage(e.getMessage());
                        }
                    }
                }
            }

            uploadPersonTemplateValidate.setAllSaved(allSaved); // 保存结果
            return uploadPersonTemplateValidate;
        }
    }
}
